package {
	import flash.display.DisplayObjectContainer;
	import flash.display.Graphics;
	import flash.display.Shape;
	import flash.display.Sprite;
	import flash.display.StageAlign;
	import flash.display.StageScaleMode;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.geom.Point;
	
	[SWF(width=400,height=700)]
	public class Bubble extends Sprite
	{
		/**
		 * 自动计算位置
		 * 删除小球
		 * 消除漂浮的小球
		 */ 
		private var model:BubbleModel = BubbleModel.instance;
		
		public function Bubble()
		{
			stage.scaleMode = StageScaleMode.NO_SCALE;
			stage.align = StageAlign.TOP_LEFT;
			stage.frameRate = 40;
			this.addEventListener(Event.ADDED_TO_STAGE,addToStageHandler);
			//Mouse.hide();
		}
		 
		private function addToStageHandler(event:Event):void {
			this.removeEventListener(Event.ADDED_TO_STAGE,addToStageHandler);
			this.createChildren();
			this.createBubbles();
			this.configEvent();
		}
		
		private function configEvent():void {
			this.stage.addEventListener(MouseEvent.CLICK,shoot);
			this.stage.addEventListener(MouseEvent.MOUSE_MOVE,mouseMoveHandler);
		}
		
		private var _row:int = 6;
		
		public function get row():int {
			return 10;
		}
		
		private var container:Sprite;
		
		private var _cloumn:int = 6;
		public function get cloumn():int {
			return 20;
		}
		
		private var showLine:int = 5;
		private function createChildren():void {
			container = new Sprite();
			this.addChild(container);
			this.animBubble = new BubbleSprite();
			this.animBubble.color = 0xFF99AA;
			this.animBubble.radius = Config.RADIUS;
			this.animBubble.redraw();
			this.addChild(this.animBubble);
			this.animBubble.x = (this.stage.stageWidth - this.animBubble.width)  / 2;
			this.animBubble.y = (this.stage.stageHeight - this.animBubble.height / 2);
			tutorialLine = new Sprite();
			this.addChild(this.tutorialLine);
		}
		
		private var tutorialLine:Sprite;
		
		private var maxHIndex:int = 0;
		private function mouseMoveHandler(event:MouseEvent):void {
			this.removeAllChildren(this.tutorialLine);
			var dx:Number = mouseX - animBubble.x;
			var dy:Number = mouseY - animBubble.y;
			/* var a:Number = Math.atan2(dy,dx);
			var px:Number = mouseX;// * angle;
			var py:Number = mouseY * a;
			px = Math.cos(a) * mouseX;
			py = Math.sin(a) * mouseY; */
			/**
			 * 1.求出沿着mouseX,mouseY的最长距离
			 * 2.如果撞墙之后需要反射
			 */ 
			/* var objects:Array = this.stage.getObjectsUnderPoint(new Point(px,py));
			for(var i:int = 0; i < objects.length; i++){
				var child:* = objects[i];
				var p:DisplayObject = 
				-
			} */
			a = Math.atan2(dy,dx);
			var tx:Number = Math.cos(a) * speed;
			var ty:Number = Math.sin(a) * speed;
			/* var px:Number = (mouseX  + 0 * tx);// TODO 这里有一个公式，应该是可以算出来，这里用了最笨的方法 
			var py:Number = (mouseY  + 0 * ty); */
			var px:Number = mouseX/*  + 10 * tx */;//(mouseX > this.stage.stageWidth / 2) ? Config.RADIUS : this.stage.stageWidth;
			var py:Number = mouseY/*  + 10 * ty */;
			/* if(px < 0){
				px = 0;
			} */
			var direction:int = mouseX > this.stage.stageWidth / 2 ? 1 : -1;
			var flag:Point = this.drawDashed(new Point(px,py),new Point(this.animBubble.x,this.animBubble.y),10,20);
			var index:int = 0;
			var aaa:Number = 0;//this.stage.stageWidth;
			var bbb:Number = 0;
			while(flag != null && flag.y > 0 && flag.y < 700){
				if(direction == 1){
					aaa = 0;
					bbb = this.stage.stageWidth;
				}else {
					aaa = this.stage.stageWidth;
					bbb = this.tutorialLine.x;
				}
				flag = this.drawDashed(new Point(aaa,flag.y + cc * ty),
										new Point(bbb,flag.y));
										index++;
										if(aaa == this.stage.stageWidth){
											aaa = Config.RADIUS;
										}else {
											aaa = this.stage.stageWidth;
										}
										direction *= -1;
			}
		}
		
		private var cc:int = 15;
		
		private function removeAllChildren($parent:DisplayObjectContainer):void {
			if(!$parent){
				return;
			}
			while($parent.numChildren > 0){
				$parent.removeChildAt(0);
			}
		}
		
		private var list:Array = [];
		private var a:Number = 0;
		public function drawDashed(p1:Point,p2:Point,length:Number=10,gap:Number=20):Point {
            var max:Number = Point.distance(p1,p2);      
            var index:Number = max;      
            var p3:Point;      
            var result:Point;
            while(index > 0){      
                p3 = Point.interpolate(p2,p1,index / max);      
                index -= length;
                var shape:Shape = this.getDot();
                shape.x = p3.x;
                shape.y = p3.y;
                this.tutorialLine.addChild(shape);
                if(p3.x - Config.RADIUS < 0){// 左
					result = p3;
				}
				if(p3.x > this.stage.stageWidth - Config.RADIUS) {// 右
					result = p3;
				}
            }     
            return result; 
        }
        
        private function getDot():Shape {
        	var shape:Shape = new Shape();
        	var g:Graphics = shape.graphics;
        	g.clear();
        	g.beginFill(0xFF99AA,1);
        	g.drawCircle(0,0,2.5);
        	return shape;
        }
        
        private function hasItem(position:Point):Boolean {
        	var result:Boolean;
        	var yIndex:uint = Math.floor(position.y / Config.DIAMETER);
			var isSingleLine:Boolean = yIndex % 2 == 0;
			var xIndex:uint;
			if(isSingleLine){
				xIndex = Math.floor(position.x / Config.DIAMETER);
			}else {
				xIndex = Math.floor((position.x - Config.RADIUS) / Config.DIAMETER);
			}
			var bubbleSprite:BubbleSprite = model.getItem(yIndex,xIndex);
			result = bubbleSprite != null;
			return result;
        }
		
		private function createBubbles():void {
			var startY:int = Config.RADIUS;
			var colors:Array = [0xFF99AA,0x2299AA,0x556222];
			for(var i:int = 0; i < cloumn; i++){
				model.items[i] = new Array();
				var isSingleLine:Boolean = i % 2 == 0;
				var zRow:int = isSingleLine ? row : row - 1;
				var startX:int = isSingleLine ? Config.RADIUS : Config.DIAMETER;
				for(var j:int = 0; j < zRow; j++){
					if(i <= showLine){
						var bubbleSprite:BubbleSprite = new BubbleSprite();
						bubbleSprite.color = colors[int(Math.random() * 2)];
						bubbleSprite.radius = Config.RADIUS;
						bubbleSprite.redraw();
						bubbleSprite.x = startX;
						bubbleSprite.y = startY;
						bubbleSprite.addLabel("" + j + "," + i);;
						//bubbleSprite.addEventListener(MouseEvent.CLICK,testing);
						startX += Config.DIAMETER;
						//if(j %5 != 0){
						
							container.addChild(bubbleSprite);
							model.setItem(i,j,bubbleSprite);
						//}
					}else{
						model.setItem(i,j,null);
					}
				}
				startY += Config.DIAMETER;
			}
			this.maxHIndex = this.showLine;
		}
		
		private function testing(event:MouseEvent):void {
			var bubbleSprite:BubbleSprite = event.target as BubbleSprite;
			bubbleSprite.addLabel("center");
			var yIndex:uint = Math.floor(bubbleSprite.y / Config.DIAMETER);
			var isSingleLine:Boolean = yIndex % 2 == 0;
			var xIndex:uint;
			if(isSingleLine){
				xIndex = Math.floor(bubbleSprite.x / Config.DIAMETER);
			}else {
				xIndex = Math.floor((bubbleSprite.x - Config.RADIUS) / Config.DIAMETER);
			}
			var list:Array = this.getAroundPoints(xIndex,yIndex);
			for(var i:int = 0; i < list.length; i++){
				var object:Object = list[i];
				var position:Point = object.position;
				var targetBubbleSprite:BubbleSprite = model.getItem(position.y,position.x);;
				if(targetBubbleSprite){
					targetBubbleSprite.addLabel(object.label);
				}
			}
		}
		
		private var animBubble:BubbleSprite;
		private var nextBubble:BubbleSprite;
		 
		private var _vx:Number = 0;
		private var _vy:Number = 0;
		
		private var speed:Number = 20;
		
		private var isRunning:Boolean = false;// 正在运行
		private var angle:Number;
		public function shoot(event:MouseEvent):void {
			if(this.isRunning){
				return;
			}
			this.tutorialLine.graphics.clear();
			this.isRunning = true;
			var dx:Number = mouseX - animBubble.x;
			var dy:Number = mouseY - animBubble.y;
			angle = Math.atan2(dy,dx);
			this._vx = Math.cos(angle) * speed;
			this._vy = Math.sin(angle) * speed;
			this.addEventListener(Event.ENTER_FRAME,enterFrameHandler);
		}
		
		private function checkHitWall():void {
			if(this.animBubble.x - Config.RADIUS <= 0){// 左
				this.animBubble.x = Config.RADIUS;
				this._vx *= -1;
			}
			if(this.animBubble.x >= this.stage.stageWidth - Config.RADIUS) {// 右
				this.animBubble.x = this.stage.stageWidth - Config.RADIUS;
				this._vx *= -1;
			}
		}
		
		private function enterFrameHandler(event:Event):void {
			if(!this.isHitBubbles()){
				this.checkHitWall();// 检测是否撞墙
				this.animBubble.x += this._vx;
				this.animBubble.y += this._vy;
			}else {// 如果碰撞到小球了
				this.hitBubbleHandler();
			}
		}
		
		private function isHitBubbles():Boolean {
			for(var i:int = 0; i < model.items.length; i++){
				var childs:Array = model.items[i];
				for(var j:int = 0; j < childs.length; j++) {
					var bubbleSprite:BubbleSprite = childs[j];
					if(bubbleSprite){
						/**if(this.animBubble.hitTestObject(bubbleSprite)){
							return true;
						}*/
						var distance:Number = Math.sqrt(Math.pow(bubbleSprite.x - this.animBubble.x,2) + Math.pow(bubbleSprite.y - this.animBubble.y,2));
						if(distance <= Config.DIAMETER){
							return true;
						}
					}
				}
			}
			return false;
		}
		
		private function hitBubbleHandler():void {
			this.removeEventListener(Event.ENTER_FRAME,enterFrameHandler);
			this.adjustPosition();
			this.createNextBubbleSprite();
		}
		
		private function createNextBubbleSprite():void {
			this.nextBubble = new BubbleSprite();
			this.nextBubble.color = 0xFF99AA;
			this.nextBubble.radius = Config.RADIUS;
			this.nextBubble.redraw();
			this.addChild(this.nextBubble);
			this.nextBubble.x = (this.stage.stageWidth - this.nextBubble.width) >> 1;
			this.nextBubble.y = (this.stage.stageHeight - this.nextBubble.height / 2);
			this.animBubble = this.nextBubble;
		}
		
		/**
		 * 如果是双行的话,那么起点应该是从一个直径的方向开始
		 * 如果是单行的话,那么起点应该是从一个半径的方向开始
		 */ 
		private function adjustPosition():void {
			var xIndex:uint;
			var yIndex:uint = Math.floor(this.animBubble.y / Config.DIAMETER);
			if(yIndex > this.maxHIndex){
				this.maxHIndex = yIndex;
			}
			var isSingleLine:Boolean = yIndex % 2 == 0;
			if(isSingleLine){
				xIndex = Math.floor(this.animBubble.x / Config.DIAMETER);
			}else {
				xIndex = Math.floor((this.animBubble.x - Config.RADIUS) / Config.DIAMETER);
			}
			if(model.getItem(yIndex,xIndex) == null){
				this.relocation(xIndex,yIndex,this.animBubble);
			}else{
				this.reset(xIndex,yIndex);
			}
			this.checkBubbleDeleted(xIndex,yIndex);
			isRunning = false;
		}
		
		/**
		 * 位置的具体算法
		 */ 
		private function getAroundPoints(xIndex:int,yIndex:int):Array {
			var result:Array = [];
			var isSingleLine:Boolean = yIndex % 2 == 0;
			if(xIndex > 0){// 左边
				result.push({position:new Point(xIndex - 1,yIndex),label:"l"});
			}
			if(xIndex < row){// 右边
				result.push({position:new Point(xIndex + 1,yIndex),label:"r"});
			}
			if(isSingleLine){
				if(xIndex > 0 && yIndex > 0){// 左上
					result.push({position:new Point(xIndex - 1, yIndex - 1),label:"tl"});
				}
			}else {
				if(xIndex > 0 && yIndex > 0){// 左上 TODO注意这个细节
					result.push({position:new Point(xIndex, yIndex - 1),label:"tl"});
				}
			} 
			 if(isSingleLine){
				if(xIndex < row && yIndex > 0){// 右上
					result.push({position:new Point(xIndex,yIndex - 1),label:"tr"});
				}
			}else {
				if(xIndex < row && yIndex > 0){// 右上
					result.push({position:new Point(xIndex + 1,yIndex - 1),label:"tr"});
				}
			} 
			if(isSingleLine){
				if(xIndex > 0 && yIndex < 10){// 左下
					result.push({position:new Point(xIndex - 1, yIndex + 1),label:"bl"});
				}
			}else {
				if(xIndex > 0 && yIndex < 10){// 左下
					result.push({position:new Point(xIndex, yIndex + 1),label:"bl"});
				}
			} 
			if(isSingleLine){
				if(xIndex < row && yIndex < 10) {// 右下
					result.push({position:new Point(xIndex,yIndex + 1),label:"br"});
				}
			}else {
				if(xIndex < row && yIndex < 10) {// 右下
					result.push({position:new Point(xIndex + 1,yIndex + 1),label:"br"});
				}
			}
			return result;
		}
		
		private function relocation(xIndex:int,yIndex:int,target:DisplayObjectContainer):void {
			var isSingleLine:Boolean = yIndex % 2 == 0;
			if(isSingleLine){
				target.x = xIndex * Config.DIAMETER + Config.RADIUS;
			}else {
				target.x = xIndex * Config.DIAMETER + Config.DIAMETER;
			}
			target.y = yIndex * Config.DIAMETER + Config.RADIUS;
			(target as BubbleSprite).addLabel(xIndex + "," + yIndex);
			model.setItem(yIndex,xIndex,target);
			trace("relocation !!!!!!!!!!!");
		}
		
		/**
		 * TODO 这个方法还需要测试
		 */ 
		private function reset(xIndex:int,yIndex:int):void {
			var points:Array = this.getAroundPoints(xIndex,yIndex);
			var distance:Number = int.MAX_VALUE;
			var d:Number;
			var xIndexReset:int;
			var yIndexReset:int;
			for(var i:int = 0; i < points.length; i++){
				var object:Object = points[i];
				var position:Point = object.position;
				var xIndex:int = position.x;
				var yIndex:int = position.y;
				var isSingleLine:Boolean = yIndexReset % 2 == 0
				var offsetX:Number = isSingleLine ? 0 : Config.RADIUS;
				var xx:Number = xIndex * Config.DIAMETER + offsetX;
				var yy:Number = yIndex * Config.DIAMETER;
				d = Math.sqrt(Math.pow(this.animBubble.x - xx,2) + Math.pow(this.animBubble.y - yy,2));
				if(d < distance){
					distance = d;
					xIndexReset = xIndex;
					yIndexReset = yIndex;
				}
			}
			this.relocation(xIndexReset,yIndexReset,this.animBubble);
		}
		
		private function checkBubbleDeleted(xIndex:int,yIndex:int):void {
			model.initialize();
			var bubbleSprite:BubbleSprite = model.getItem(yIndex,xIndex);
			var color:uint = bubbleSprite.color;
			var position:Point = new Point(xIndex,yIndex)
			model.addCheckedToBubbles(position);
			model.deletedToBubbles.push(position);
			this.recursion(position.x,position.y,color);
			if(model.canRemove){
				for(var i:int = 0; i < model.deletedToBubbles.length; i++){
					position = model.deletedToBubbles[i];
					var removedBubbleSprite:BubbleSprite = model.getItem(position.y,position.x);
					if(removedBubbleSprite){
						removedBubbleSprite.parent.removeChild(removedBubbleSprite);
						model.setItem(position.y,position.x,null);
					}
				}
			}else {
				
			}
			model.checkedToBubbles = [];
			this.deletedHangBubble(xIndex,yIndex);
		}
		
		private function recursion(xIndex:int,yIndex:int,color:uint):void {
			var list:Array = this.getAroundPoints(xIndex,yIndex);
			for(var i:int = 0; i < list.length; i++){
				var position:Point = list[i].position;
				var bubbleSprite:BubbleSprite = model.getItem(position.y,position.x);
				if(bubbleSprite != null && !model.hasObjectInCheckedToBubbles(position)){
					model.addCheckedToBubbles(position);
					if(bubbleSprite.color == color){
						model.deletedToBubbles.push(position);
						recursion(position.x,position.y,color);
					}
				}
			}
		}
		
		private var bubbleList:Array;
		
		private function deletedHangBubble(xIndex:int,yIndex:int):void {
			bubbleList = [];
			model.checkedToBubbles = [];
			for(var i:int = 0; i < model.items.length; i++){
				bubbleList.push(new Array());
				var childs:Array = model.items[i];
				for(var j:int = 0; j < childs.length; j++){
					var bubbleSprite:BubbleSprite = childs[j];
					if(bubbleSprite != null){
						bubbleList[i][j] = 1;
					}
				}
			}
			bubbleList[yIndex][xIndex] = 0;
			var count:int = 10;
			for(var k:int = 0; k < count; k++){
				if(model.getItem(0,k) != null && !model.hasObjectInCheckedToBubbles(new Point(0,k))){
					model.addCheckedToBubbles(new Point(0,k));
					bubbleList[0][k] = 0;
					hangBubbleRecursion(k,0);
				}
			}
			this.removeHangBubbles();
		}
		
		private function removeHangBubbles():void {
			for(var i:int = 0; i < bubbleList.length; i++){
				var childs:Array = bubbleList[i];
				for(var j:int = 0; j < childs.length; j++){
					var index:int = childs[j];
					if(index == 1){
						var bubbleSprite:BubbleSprite = model.getItem(i,j);
						/* if(bubbleSprite){
							bubbleSprite.addLabel("d");
							model.setItem(i,j,null);
						} */
						if(bubbleSprite){
							bubbleSprite.parent.removeChild(bubbleSprite);
							model.setItem(i,j,null);
						} 
					}
				}
			}
		}
		
		private function hangBubbleRecursion(xIndex:int,yIndex:int):void {
			var points:Array = this.getAroundPoints(xIndex,yIndex);
			for(var i:int = 0; i < points.length; i++){
				var position:Point = points[i].position;
				var bubbleSprite:BubbleSprite = model.getItem(position.y,position.x);
				if(bubbleSprite != null){
					if(!model.hasObjectInCheckedToBubbles(position)){
						model.addCheckedToBubbles(position);
						bubbleList[position.y][position.x] = 0;
						hangBubbleRecursion(position.x,position.y);
					}else {
						//trace("checked " + position.x + " : " + position.y);
					}
				}
			}
		}
	}
}
